.altmacro
.macro SAVE_SN n
    sd s\n, (\n+1)*8(sp)
.endm
.macro LOAD_SN n
    ld s\n, (\n+1)*8(sp)
.endm
    .section .text
    .globl __switch
__switch:
    # __switch(
    #     current_task_ctx_ptr2: &*const TaskContext,
    #     next_task_ctx_ptr2: &*const TaskContext
    # )
    # 在现在的栈上申请一个 TaskContext 大小的空间
    addi sp, sp, -13*8
    # 再将 sp 存到 a0 偏移0处, 
    # 即: 将 current_task_ctx_ptr2 指向新的 TaskContext 的指针 (sp)
    sd sp, 0(a0)
    # 为新的 current_task_ctx 赋值
    sd ra, 0(sp)
    .set n, 0
    .rept 12
        SAVE_SN %n
        .set n, n + 1
    .endr
    # 将 sp 切换到 next_task_context 所在的栈上
    ld sp, 0(a1)
    # 根据栈上的 TaskContext 恢复寄存器的值
    ld ra, 0(sp) # 恢复 ra 寄存器
    .set n, 0    # 恢复 s1-11 寄存器
    .rept 12
        LOAD_SN %n 
        .set n, n + 1
    .endr
    # 释放栈上的 TaskContext 的空间
    addi sp, sp, 13*8
    ret # 跳转到 ra 寄存器所储存的地址处

    # 第一次运行时:          current_task (a0) -> addr: 0x0 (file:///./mod.rs)
    # |    | <- sp |Trap|
    # |    |       |Task| <- n_task_ptr2 (a1)
    # |    |       |    |
    # current       next

    # addi sp, sp, -13*8
    
    # |    |       |Trap|
    # |    | <- sp |Task| <- n_task_ptr2 (a1)
    # |    |       |    |
    # current       next

    # sd sp, 0(a0)

    #                     |    |       |Trap| 
    # (a0) c_task_ptr2 -> |    | <- sp |Task| <- n_task_ptr2 (a1)
    #                     |    |       |    |
    #                     current       next

    # la ra, 0(sp) 这一步很关键, 这一步设置了TaskContext中的返回地址
    # .set
    #   ...
    # .endr

    #                     |    |       |Trap| 
    # (a0) c_task_ptr2 -> |Task| <- sp |Task| <- n_task_ptr2 (a1)
    #                     |    |       |    |
    #                     current       next

    # ld sp, 0(a1)

    #                     |    |       |Trap| 
    # (a0) c_task_ptr2 -> |Task| sp -> |Task| <- n_task_ptr2 (a1)
    #                     |    |       |    |
    #                     current       next

    # 根据 next 栈上的 TaskContext 恢复
    # ld ra, 0(sp)
    # .set 
    #     ...
    # .endr

    # 释放栈上的 TaskContext 的空间

    #                     |    | sp -> |Trap| 
    # (a0) c_task_ptr2 -> |Task|       |    | <- n_task_ptr2 (a1)
    #                     |    |       |    |
    #                     current       next

    # ret 跳转到 ra 寄存器保存的地址处运行
    # 第一次运行时 ra = __restore (file:///./context.rs)
    # 而 sp 刚好指向 TrapContext
    # 而且 这个 TrapContext 刚好初始化 sepc 为 entry (应用入口) (file:///./../trap/context.rs)
    # 所以就可以开始运行